package com.syf.starter.core.netty.tool.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.syf.core.service.SyServiceDefinition;
import com.syf.core.service.context.ServiceRequest;
import com.syf.core.service.context.ServiceResponse;
import com.syf.starter.HttpServerCont;
import com.syf.starter.core.netty.tool.MsgCovert;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.multipart.Attribute;
import io.netty.handler.codec.http.multipart.DefaultHttpDataFactory;
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
import io.netty.handler.codec.http.multipart.InterfaceHttpData;
import io.netty.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

@Slf4j
public class HttpMsgConvert implements MsgCovert<FullHttpRequest> {
    private final ObjectMapper jsonMapper;

    private final XmlMapper xmlMapper;

    private static HttpMsgConvert INSTANCE;

    public static HttpMsgConvert getINSTANCE(ObjectMapper jsonMapper, XmlMapper xmlMapper) {
        if (INSTANCE == null) {
            INSTANCE = new HttpMsgConvert(jsonMapper, xmlMapper);
        }
        return INSTANCE;
    }

    private HttpMsgConvert(ObjectMapper jsonMapper, XmlMapper xmlMapper) {
        this.jsonMapper = jsonMapper;
        this.xmlMapper = xmlMapper;
    }

    public Map<String, String> convertHeadersToMap(FullHttpRequest request) {
        // 创建结果Map
        Map<String, String> headersMap = new HashMap<>();

        // 获取请求头部
        HttpHeaders headers = request.headers();

        // 遍历所有头部字段
        Iterator<Map.Entry<String, String>> iterator = headers.iteratorAsString();
        while (iterator.hasNext()) {
            Map.Entry<String, String> entry = iterator.next();
            headersMap.put(entry.getKey().toLowerCase(), entry.getValue());
        }

        return headersMap;
    }

    @Override
    public ServiceRequest buildServiceRequest(SyServiceDefinition serviceDefinition, FullHttpRequest request) throws Exception {
        String contentType = request.headers().get(HttpHeaderNames.CONTENT_TYPE);
        CharSequence mediaType = HttpHeaderValues.APPLICATION_JSON.toString();
        if (contentType != null) {
            mediaType = HttpUtil.getMimeType(contentType);
        }

        ServiceRequest serviceRequest = new ServiceRequest(HttpServerCont.HTTP_SERVER_APP_COMPONENT_NAME);
        // 设置http headers
        serviceRequest.getHead().setHeadItems(convertHeadersToMap(request));

        // 将query string转map
        QueryStringDecoder queryStringDecoder = new QueryStringDecoder(request.uri());

        Map<String, String> queryParams = new HashMap<>();
        queryStringDecoder.parameters().forEach((key, values) -> {
            if (!values.isEmpty()) {
                queryParams.put(key, values.get(0));
            }
        });

        if (contentType != null) {
            if (HttpHeaderValues.APPLICATION_JSON.contentEqualsIgnoreCase(mediaType)) {
                // json
                try {
                    String reqContent = request.content().toString(CharsetUtil.UTF_8);
                    if (StrUtil.isBlank(reqContent)) {
                        reqContent = "{}";
                    }
                    if (log.isDebugEnabled()) {
                        log.debug("收到原始报文：{}", reqContent);
                    }
                    Object reqDataObj = jsonMapper.readValue(reqContent, serviceDefinition.getRequestClass());
                    serviceRequest.setDataObj(reqDataObj);
                } catch (JsonProcessingException e) {
                    throw new RuntimeException(e);
                }
            } else if (HttpHeaderValues.APPLICATION_X_WWW_FORM_URLENCODED.contentEqualsIgnoreCase(mediaType)) {
                // form 表单
                HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(new DefaultHttpDataFactory(false), request);
                Map<String, String> formData = new HashMap<>();
                try {
                    List<InterfaceHttpData> postData = decoder.getBodyHttpDatas(); // Get the list of HTTP data
                    for (InterfaceHttpData data : postData) {
                        if (data.getHttpDataType() == InterfaceHttpData.HttpDataType.Attribute) {
                            Attribute attribute = (Attribute) data;
                            formData.put(attribute.getName(), attribute.getValue());
                        }
                    }
                    Object reqDataObj = BeanUtil.toBean(formData, serviceDefinition.getRequestClass());
                    serviceRequest.setDataObj(reqDataObj);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                } finally {
                    decoder.destroy();
                }
            } else if (HttpHeaderValues.APPLICATION_XML.contentEqualsIgnoreCase(mediaType) || HttpHeaderValues.XML_HTTP_REQUEST.contentEqualsIgnoreCase(mediaType)) {
                // xml
                String reqContent = request.content().toString(CharsetUtil.UTF_8);
                if (log.isDebugEnabled()) {
                    log.debug("收到原始报文：{}", reqContent);
                }
                try {
                    Object reqDataObj = xmlMapper.readValue(reqContent, serviceDefinition.getRequestClass());
                    serviceRequest.setDataObj(reqDataObj);
                } catch (JsonProcessingException e) {
                    throw new RuntimeException(e);
                }

            } else {
                throw new RuntimeException("暂时只支持application/json,application/x-www-form-urlencoded,application/xml,XMLHttpRequest");
            }
        } else {
            // 按get url 传参方式
            request.headers().set(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_X_WWW_FORM_URLENCODED.toString());
            Object reqDataObj = BeanUtil.toBean(new HashMap<String, Object>(), serviceDefinition.getRequestClass());
            serviceRequest.setDataObj(reqDataObj);
        }

        // 将url中query param 加载至请求对象中
        BeanUtil.copyProperties(queryParams, serviceRequest.getDataObj());
        return serviceRequest;
    }

    @Override
    public ServiceRequest convertRequest(SyServiceDefinition serviceDefinition, FullHttpRequest msg) throws Exception {
        return MsgCovert.super.convertRequest(serviceDefinition, msg);
    }

    @Override
    public ByteBuf convertResponse(FullHttpRequest requestMsg, ServiceResponse response) throws Exception {
        String contentType = requestMsg.headers().get(HttpHeaderNames.CONTENT_TYPE);
        CharSequence mediaType = HttpUtil.getMimeType(contentType);
        if (contentType == null || HttpHeaderValues.APPLICATION_X_WWW_FORM_URLENCODED.contentEqualsIgnoreCase(mediaType)) {
            StringBuilder sb = new StringBuilder();
            sb.append("respCode=").append(response.getRespCode()).append("&respMsg=").append(response.getRespMsg());

            Map<String, Object> respMap = BeanUtil.beanToMap(response.getDataObj(), false, true);
            if (respMap != null) {
                for (Map.Entry<String, Object> entry : respMap.entrySet()) {
                    sb.append("&").append(entry.getKey()).append("=").append(entry.getValue());
                }
            }

            return Unpooled.wrappedBuffer(jsonMapper.writeValueAsString(sb.toString()).getBytes(StandardCharsets.UTF_8));
        } else if (HttpHeaderValues.APPLICATION_JSON.contentEqualsIgnoreCase(mediaType)) {
            return Unpooled.wrappedBuffer(jsonMapper.writeValueAsString(response).getBytes(StandardCharsets.UTF_8));
        } else if (HttpHeaderValues.APPLICATION_XML.contentEqualsIgnoreCase(mediaType) || HttpHeaderValues.XML_HTTP_REQUEST.contentEqualsIgnoreCase(mediaType)) {
            return Unpooled.wrappedBuffer(xmlMapper.writeValueAsString(response).getBytes(StandardCharsets.UTF_8));
        } else {
            throw new RuntimeException("暂时只支持application/json,application/x-www-form-urlencoded,application/xml,XMLHttpRequest");
        }
    }
}
